home *** CD-ROM | disk | FTP | other *** search
/ Total Network Tools 2002 / NextStepPublishing-TotalNetworkTools2002-Win95.iso / Archive / Misc Servers / Zope.exe / SIMPLEITEM.PY < prev    next >
Encoding:
Python Source  |  2000-06-12  |  14.9 KB  |  417 lines

  1. ##############################################################################
  2. # Zope Public License (ZPL) Version 1.0
  3. # -------------------------------------
  4. # Copyright (c) Digital Creations.  All rights reserved.
  5. # This license has been certified as Open Source(tm).
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions are
  8. # met:
  9. # 1. Redistributions in source code must retain the above copyright
  10. #    notice, this list of conditions, and the following disclaimer.
  11. # 2. Redistributions in binary form must reproduce the above copyright
  12. #    notice, this list of conditions, and the following disclaimer in
  13. #    the documentation and/or other materials provided with the
  14. #    distribution.
  15. # 3. Digital Creations requests that attribution be given to Zope
  16. #    in any manner possible. Zope includes a "Powered by Zope"
  17. #    button that is installed by default. While it is not a license
  18. #    violation to remove this button, it is requested that the
  19. #    attribution remain. A significant investment has been put
  20. #    into Zope, and this effort will continue if the Zope community
  21. #    continues to grow. This is one way to assure that growth.
  22. # 4. All advertising materials and documentation mentioning
  23. #    features derived from or use of this software must display
  24. #    the following acknowledgement:
  25. #      "This product includes software developed by Digital Creations
  26. #      for use in the Z Object Publishing Environment
  27. #      (http://www.zope.org/)."
  28. #    In the event that the product being advertised includes an
  29. #    intact Zope distribution (with copyright and license included)
  30. #    then this clause is waived.
  31. # 5. Names associated with Zope or Digital Creations must not be used to
  32. #    endorse or promote products derived from this software without
  33. #    prior written permission from Digital Creations.
  34. # 6. Modified redistributions of any form whatsoever must retain
  35. #    the following acknowledgment:
  36. #      "This product includes software developed by Digital Creations
  37. #      for use in the Z Object Publishing Environment
  38. #      (http://www.zope.org/)."
  39. #    Intact (re-)distributions of any official Zope release do not
  40. #    require an external acknowledgement.
  41. # 7. Modifications are encouraged but must be packaged separately as
  42. #    patches to official Zope releases.  Distributions that do not
  43. #    clearly separate the patches from the original work must be clearly
  44. #    labeled as unofficial distributions.  Modifications which do not
  45. #    carry the name Zope may be packaged in any form, as long as they
  46. #    conform to all of the clauses above.
  47. # Disclaimer
  48. #   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
  49. #   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  50. #   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  51. #   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
  52. #   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  53. #   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  54. #   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  55. #   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  56. #   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  57. #   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  58. #   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  59. #   SUCH DAMAGE.
  60. # This software consists of contributions made by Digital Creations and
  61. # many individuals on behalf of Digital Creations.  Specific
  62. # attributions are listed in the accompanying credits file.
  63. ##############################################################################
  64. '''This module implements a simple item mix-in for objects that have a
  65. very simple (e.g. one-screen) management interface, like documents,
  66. Aqueduct database adapters, etc.
  67.  
  68. This module can also be used as a simple template for implementing new
  69. item types. 
  70.  
  71. $Id: SimpleItem.py,v 1.78 2000/06/12 19:49:48 shane Exp $'''
  72. __version__='$Revision: 1.78 $'[11:-2]
  73.  
  74. import regex, sys, Globals, App.Management, Acquisition, App.Undo
  75. import AccessControl.Role, AccessControl.Owned, App.Common
  76. from webdav.Resource import Resource
  77. from ExtensionClass import Base
  78. from DateTime import DateTime
  79. from CopySupport import CopySource
  80. from string import join, lower, find, split
  81. from types import InstanceType, StringType
  82. from ComputedAttribute import ComputedAttribute
  83. from AccessControl import getSecurityManager
  84. from Traversable import Traversable
  85.  
  86. import marshal
  87. import ZDOM
  88.  
  89. HTML=Globals.HTML
  90. StringType=type('')
  91.  
  92. class Item(Base, Resource, CopySource, App.Management.Tabs, Traversable,
  93.            ZDOM.Element,
  94.            AccessControl.Owned.Owned,
  95.            App.Undo.UndoSupport,
  96.            ):
  97.     """A common base class for simple, non-container objects."""
  98.     isPrincipiaFolderish=0
  99.     isTopLevelPrincipiaApplicationObject=0
  100.     
  101.     def manage_afterAdd(self, item, container): pass
  102.     def manage_beforeDelete(self, item, container): pass
  103.     def manage_afterClone(self, item): pass
  104.  
  105.     # The name of this object and the name used to traverse to thie
  106.     # object in a URL:
  107.     id=''
  108.  
  109.     # Alias id to __name__, which will make tracebacks a good bit nicer:
  110.     __name__=ComputedAttribute(lambda self: self.id)
  111.  
  112.     # Name, relative to SOFTWARE_URL of icon used to display item
  113.     # in folder listings.
  114.     icon=''
  115.  
  116.     # Meta type used for selecting all objects of a given type.
  117.     meta_type='simple item'
  118.  
  119.     # Default title.  
  120.     title=''
  121.  
  122.     # Default propertysheet info:
  123.     __propsets__=()
  124.  
  125.     manage_options=(
  126.         App.Undo.UndoSupport.manage_options
  127.         +AccessControl.Owned.Owned.manage_options
  128.         )
  129.     
  130.     # Attributes that must be acquired
  131.     REQUEST=Acquisition.Acquired
  132.  
  133.     # Allow (reluctantly) access to unprotected attributes
  134.     __allow_access_to_unprotected_subobjects__=1
  135.  
  136.  
  137.     def title_or_id(self):
  138.         """
  139.         Utility that returns the title if it is not blank and the id
  140.         otherwise.
  141.         """
  142.         title=self.title
  143.         if callable(title):
  144.             title=title()
  145.         if title: return title
  146.         id=self.id
  147.         if callable(id):
  148.             id=id()
  149.         return id
  150.  
  151.     def title_and_id(self):
  152.         """
  153.         Utility that returns the title if it is not blank and the id
  154.         otherwise.  If the title is not blank, then the id is included
  155.         in parens.
  156.         """
  157.         title=self.title
  158.         if callable(title):
  159.             title=title()
  160.         id=self.id
  161.         if callable(id):
  162.             id=id()
  163.         return title and ("%s (%s)" % (title,id)) or id
  164.     
  165.     def this(self):
  166.         # Handy way to talk to ourselves in document templates.
  167.         return self
  168.  
  169.     def tpURL(self):
  170.         # My URL as used by tree tag
  171.         url=self.id
  172.         if hasattr(url,'im_func'): url=url()
  173.         return url
  174.  
  175.     def tpValues(self):
  176.         # My sub-objects as used by the tree tag
  177.         return ()
  178.  
  179.     _manage_editedDialog=Globals.HTMLFile('editedDialog', globals())
  180.     def manage_editedDialog(self, REQUEST, **args):
  181.         return apply(self._manage_editedDialog,(self, REQUEST), args)
  182.  
  183.     def raise_standardErrorMessage(
  184.         self, client=None, REQUEST={},
  185.         error_type=None, error_value=None, tb=None,
  186.         error_tb=None, error_message='',
  187.         tagSearch=regex.compile('[a-zA-Z]>').search):
  188.  
  189.         try:
  190.             if error_type  is None: error_type =sys.exc_info()[0]
  191.             if error_value is None: error_value=sys.exc_info()[1]
  192.             
  193.             # turn error_type into a string            
  194.             if hasattr(error_type, '__name__'):
  195.                 error_type=error_type.__name__
  196.  
  197.             # allow for a few different traceback options
  198.             if tb is None and error_tb is None:
  199.                 tb=sys.exc_info()[2]
  200.             if type(tb) is not type('') and (error_tb is None):
  201.                 error_tb=pretty_tb(error_type, error_value, tb)
  202.             elif type(tb) is type('') and not error_tb:
  203.                 error_tb=tb
  204.  
  205.             if hasattr(self, '_v_eek'):
  206.                 raise error_type, error_value, tb
  207.             self._v_eek=1
  208.    
  209.             if lower(str(error_type)) in ('redirect',):
  210.                 raise error_type, error_value, tb
  211.  
  212.             if not error_message:
  213.                 if type(error_value) is InstanceType:
  214.                     s=str(error_value)
  215.                     if tagSearch(s) >= 0:
  216.                         error_message=error_value
  217.                 elif (type(error_value) is StringType
  218.                       and tagSearch(error_value) >= 0):
  219.                     error_message=error_value
  220.  
  221.             if client is None: client=self
  222.             if not REQUEST: REQUEST=self.aq_acquire('REQUEST')
  223.  
  224.             try:
  225.                 if hasattr(client, 'standard_error_message'):
  226.                     s=getattr(client, 'standard_error_message')
  227.                 else:
  228.                     client = client.aq_parent
  229.                     s=getattr(client, 'standard_error_message')
  230.                 v=HTML.__call__(s, client, REQUEST, error_type=error_type,
  231.                                 error_value=error_value,
  232.                                 error_tb=error_tb,error_traceback=error_tb,
  233.                                 error_message=error_message)
  234.             except: v = error_value or "Sorry, an error occurred"
  235.             raise error_type, v, tb
  236.         finally:
  237.             if hasattr(self, '_v_eek'): del self._v_eek
  238.             tb=None
  239.  
  240.     def manage(self, URL1):
  241.         " "
  242.         raise 'Redirect', "%s/manage_main" % URL1 
  243.  
  244.     # This keeps simple items from acquiring their parents
  245.     # objectValues, etc., when used in simple tree tags.
  246.     def objectValues(self, spec=None):
  247.         return ()
  248.     objectIds=objectItems=objectValues
  249.  
  250.     # FTP support methods
  251.     
  252.     def manage_FTPstat(self,REQUEST):
  253.         "psuedo stat, used by FTP for directory listings"
  254.         from AccessControl.User import nobody
  255.         mode=0100000
  256.         
  257.         # check read permissions
  258.         if (hasattr(self.aq_base,'manage_FTPget') and 
  259.             hasattr(self.manage_FTPget, '__roles__')):
  260.             try:
  261.                 if getSecurityManager().validateValue(self.manage_FTPget):
  262.                     mode=mode | 0440
  263.             except: pass
  264.             if nobody.allowed(self.manage_FTPget,
  265.                               self.manage_FTPget.__roles__):
  266.                 mode=mode | 0004
  267.                 
  268.         # check write permissions
  269.         if hasattr(self.aq_base,'PUT') and hasattr(self.PUT, '__roles__'):
  270.             try:
  271.                 if getSecurityManager().validateValue(self.PUT):
  272.                     mode=mode | 0220
  273.             except: pass
  274.             
  275.             if nobody.allowed(self.PUT, self.PUT.__roles__):
  276.                 mode=mode | 0002
  277.                 
  278.         # get size
  279.         if hasattr(self, 'get_size'):
  280.             size=self.get_size()
  281.         elif hasattr(self,'manage_FTPget'):
  282.             size=len(self.manage_FTPget())
  283.         else:
  284.             size=0
  285.         # get modification time
  286.         mtime=self.bobobase_modification_time().timeTime()
  287.         # get owner and group
  288.         owner=group='Zope'
  289.         for user, roles in self.get_local_roles():
  290.             if 'Owner' in roles:
  291.                 owner=user
  292.                 break
  293.         return marshal.dumps((mode,0,0,1,owner,group,size,mtime,mtime,mtime))
  294.  
  295.     def manage_FTPlist(self,REQUEST):
  296.         """Directory listing for FTP. In the case of non-Foldoid objects,
  297.         the listing should contain one object, the object itself."""
  298.         # check to see if we are being acquiring or not
  299.         ob=self
  300.         while 1:
  301.             if App.Common.is_acquired(ob):
  302.                 raise ValueError('FTP List not supported on acquired objects')
  303.             if not hasattr(ob,'aq_parent'):
  304.                 break
  305.             ob=ob.aq_parent
  306.             
  307.         stat=marshal.loads(self.manage_FTPstat(REQUEST))
  308.         if callable(self.id): id=self.id()
  309.         else: id=self.id
  310.         return marshal.dumps((id,stat))
  311.  
  312.     def __len__(self):
  313.         return 1
  314.  
  315.  
  316. Globals.default__class_init__(Item)
  317.  
  318. class Item_w__name__(Item):
  319.     """Mixin class to support common name/id functions"""
  320.  
  321.     def title_or_id(self):
  322.         """Utility that returns the title if it is not blank and the id
  323.         otherwise."""
  324.         return self.title or self.__name__
  325.  
  326.     def title_and_id(self):
  327.         """Utility that returns the title if it is not blank and the id
  328.         otherwise.  If the title is not blank, then the id is included
  329.         in parens."""
  330.         t=self.title
  331.         return t and ("%s (%s)" % (t,self.__name__)) or self.__name__
  332.  
  333.     def _setId(self, id):
  334.         self.__name__=id
  335.  
  336.     def getPhysicalPath(self):
  337.         '''Returns a path (an immutable sequence of strings)
  338.         that can be used to access this object again
  339.         later, for example in a copy/paste operation.  getPhysicalRoot()
  340.         and getPhysicalPath() are designed to operate together.
  341.         '''
  342.         path = (self.__name__,)
  343.         
  344.         p = getattr(self,'aq_inner', None)
  345.         if p is not None: 
  346.             path = p.aq_parent.getPhysicalPath() + path
  347.             
  348.         return path
  349.  
  350.  
  351. def format_exception(etype,value,tb,limit=None):
  352.     import traceback
  353.     result=['Traceback (innermost last):']
  354.     if limit is None:
  355.         if hasattr(sys, 'tracebacklimit'):
  356.             limit = sys.tracebacklimit
  357.     n = 0
  358.     while tb is not None and (limit is None or n < limit):
  359.         f = tb.tb_frame
  360.         lineno = tb.tb_lineno
  361.         co = f.f_code
  362.         filename = co.co_filename
  363.         name = co.co_name
  364.         locals=f.f_locals
  365.         result.append('  File %s, line %d, in %s'
  366.                       % (filename,lineno,name))
  367.         try: result.append('    (Object: %s)' %
  368.                            locals[co.co_varnames[0]].__name__)
  369.         except: pass
  370.         try: result.append('    (Info: %s)' %
  371.                            str(locals['__traceback_info__']))
  372.         except: pass
  373.         tb = tb.tb_next
  374.         n = n+1
  375.     result.append(join(traceback.format_exception_only(etype, value),' '))
  376.     return result
  377.  
  378. def pretty_tb(t,v,tb):
  379.     tb=format_exception(t,v,tb,200)
  380.     tb=join(tb,'\n')
  381.     return tb
  382.  
  383. class SimpleItem(Item, Globals.Persistent,
  384.                  Acquisition.Implicit,
  385.                  AccessControl.Role.RoleManager,
  386.                  ):
  387.     # Blue-plate special, Zope Masala
  388.     """Mix-in class combining the most common set of basic mix-ins
  389.     """
  390.  
  391.     manage_options=Item.manage_options+(
  392.         {'label':'Security',   'action':'manage_access'},
  393.         )
  394.  
  395.     __ac_permissions__=(('View', ()),)
  396.